/**
 * Copyright 2010-present Facebook.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.widget;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.facebook.android.R;

import java.lang.ref.WeakReference;

public class ToolTipPopup
{

  public static enum Style
  {
    /**
     * The tool tip will be shown with a blue style; including a blue background and blue
     * arrows.
     */
    BLUE,

    /**
     * The tool tip will be shown with a black style; including a black background and black
     * arrows.
     */
    BLACK
  }

  /**
   * The default time that the tool tip will be displayed
   */
  public static final long DEFAULT_POPUP_DISPLAY_TIME = 6000;

  private final String mText;
  private final WeakReference<View> mAnchorViewRef;
  private final Context mContext;
  private PopupContentView mPopupContent;
  private PopupWindow mPopupWindow;
  private Style mStyle = Style.BLUE;
  private long mNuxDisplayTime = DEFAULT_POPUP_DISPLAY_TIME;

  private final ViewTreeObserver.OnScrollChangedListener mScrollListener =
      new ViewTreeObserver.OnScrollChangedListener()
      {
        @Override
        public void onScrollChanged()
        {
          if (mAnchorViewRef.get() != null &&
              mPopupWindow != null &&
              mPopupWindow.isShowing())
          {
            if (mPopupWindow.isAboveAnchor())
            {
              mPopupContent.showBottomArrow();
            }
            else
            {
              mPopupContent.showTopArrow();
            }
          }
        }
      };

  /**
   * Create a new ToolTipPopup
   *
   * @param text   The text to be displayed in the tool tip
   * @param anchor The view to anchor this tool tip to.
   */
  public ToolTipPopup(String text, View anchor)
  {
    mText = text;
    mAnchorViewRef = new WeakReference<View>(anchor);
    mContext = anchor.getContext();
  }

  /**
   * Sets the {@link Style} of this tool tip.
   *
   * @param mStyle
   */
  public void setStyle(Style mStyle)
  {
    this.mStyle = mStyle;
  }

  /**
   * Display this tool tip to the user
   */
  public void show()
  {
    if (mAnchorViewRef.get() != null)
    {
      mPopupContent = new PopupContentView(mContext);
      TextView body = (TextView) mPopupContent.findViewById(
          R.id.com_facebook_tooltip_bubble_view_text_body);
      body.setText(mText);
      if (mStyle == Style.BLUE)
      {
        mPopupContent.bodyFrame.setBackgroundResource(
            R.drawable.com_facebook_tooltip_blue_background);
        mPopupContent.bottomArrow.setImageResource(
            R.drawable.com_facebook_tooltip_blue_bottomnub);
        mPopupContent.topArrow.setImageResource(
            R.drawable.com_facebook_tooltip_blue_topnub);
        mPopupContent.xOut.setImageResource(R.drawable.com_facebook_tooltip_blue_xout);
      }
      else
      {
        mPopupContent.bodyFrame.setBackgroundResource(
            R.drawable.com_facebook_tooltip_black_background);
        mPopupContent.bottomArrow.setImageResource(
            R.drawable.com_facebook_tooltip_black_bottomnub);
        mPopupContent.topArrow.setImageResource(
            R.drawable.com_facebook_tooltip_black_topnub);
        mPopupContent.xOut.setImageResource(R.drawable.com_facebook_tooltip_black_xout);
      }

      final Window window = ((Activity) mContext).getWindow();
      final View decorView = window.getDecorView();
      final int decorWidth = decorView.getWidth();
      final int decorHeight = decorView.getHeight();
      registerObserver();
      mPopupContent.onMeasure(
          View.MeasureSpec.makeMeasureSpec(decorWidth, View.MeasureSpec.AT_MOST),
          View.MeasureSpec.makeMeasureSpec(decorHeight, View.MeasureSpec.AT_MOST));
      mPopupWindow = new PopupWindow(
          mPopupContent,
          mPopupContent.getMeasuredWidth(),
          mPopupContent.getMeasuredHeight());
      mPopupWindow.showAsDropDown(mAnchorViewRef.get());
      updateArrows();
      if (mNuxDisplayTime > 0)
      {
        mPopupContent.postDelayed(new Runnable()
        {
          @Override
          public void run()
          {
            dismiss();
          }
        }, mNuxDisplayTime);
      }
      mPopupWindow.setTouchable(true);
      mPopupContent.setOnClickListener(new View.OnClickListener()
      {
        @Override
        public void onClick(View v)
        {
          dismiss();
        }
      });
    }
  }

  /**
   * Set the time (in milliseconds) the tool tip will be displayed. Any number less than or equal
   * to 0 will cause the tool tip to be displayed indefinitely
   *
   * @param displayTime The amount of time (in milliseconds) to display the tool tip
   */
  public void setNuxDisplayTime(long displayTime)
  {
    this.mNuxDisplayTime = displayTime;
  }

  private void updateArrows()
  {
    if (mPopupWindow != null && mPopupWindow.isShowing())
    {
      if (mPopupWindow.isAboveAnchor())
      {
        mPopupContent.showBottomArrow();
      }
      else
      {
        mPopupContent.showTopArrow();
      }
    }
  }

  /**
   * Dismiss the tool tip
   */
  public void dismiss()
  {
    unregisterObserver();
    if (mPopupWindow != null)
    {
      mPopupWindow.dismiss();
    }
  }

  private void registerObserver()
  {
    unregisterObserver();
    if (mAnchorViewRef.get() != null)
    {
      mAnchorViewRef.get().getViewTreeObserver().addOnScrollChangedListener(mScrollListener);
    }
  }

  private void unregisterObserver()
  {
    if (mAnchorViewRef.get() != null)
    {
      mAnchorViewRef.get().getViewTreeObserver().removeOnScrollChangedListener(mScrollListener);
    }
  }

  private class PopupContentView extends FrameLayout
  {
    private ImageView topArrow;
    private ImageView bottomArrow;
    private View bodyFrame;
    private ImageView xOut;

    public PopupContentView(Context context)
    {
      super(context);
      init();
    }

    private void init()
    {
      LayoutInflater inflater = LayoutInflater.from(getContext());
      inflater.inflate(R.layout.com_facebook_tooltip_bubble, this);
      topArrow = (ImageView) findViewById(R.id.com_facebook_tooltip_bubble_view_top_pointer);
      bottomArrow = (ImageView) findViewById(
          R.id.com_facebook_tooltip_bubble_view_bottom_pointer);
      bodyFrame = findViewById(R.id.com_facebook_body_frame);
      xOut = (ImageView) findViewById(R.id.com_facebook_button_xout);
    }

    public void showTopArrow()
    {
      topArrow.setVisibility(View.VISIBLE);
      bottomArrow.setVisibility(View.INVISIBLE);
    }

    public void showBottomArrow()
    {
      topArrow.setVisibility(View.INVISIBLE);
      bottomArrow.setVisibility(View.VISIBLE);
    }

    // Expose so popup content can be sized
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
  }
}
